package com.zs.utils;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.Map;

/**
 * @author ZhouShuang
 * @version 17
 * @Title
 * @date 2025/6/9 上午10:15
 */
public class RequestToBean {

    /**
     * 将请求信息通过反射封装成JavaBean对象
     *
     * @param request   HttpServletRequest对象
     * @param beanClass javaBean的Class对象
     * @param <T>
     * @return 封装好的JavaBean
     */
    public static <T> T convert(HttpServletRequest request, Class<T> beanClass) {
        try {
            //获取请求参数Map
            Map<String, String[]> map = request.getParameterMap();
            //创建JavaBean对象
            T bean = beanClass.newInstance();

            //遍历所有的请求参数
            for (Map.Entry<String, String[]> entry : map.entrySet()) {
                String paramName = entry.getKey();
                String[] paramValue = entry.getValue();
                //如果参数有值
                if (paramName != null && paramValue.length > 0) {
                    //获取参数对应的JavaBean属性
                    Field field = beanClass.getDeclaredField(paramName);
                    //获取参数对应JavaBean属性的setter
                    String setterName = "set" + paramName.substring(0, 1).toUpperCase() + paramName.substring(1);
                    Method setter = beanClass.getDeclaredMethod(setterName, field.getType());
                    //将请求的参数值类型转化为对应JavaBean字段的类型
                    Object value = parseValue(paramValue, field.getType());
                    //调用JavaBean属性的setter方法
                    setter.invoke(bean, value);
                }
                Method[] allMethods = beanClass.getDeclaredMethods();
                for (Method allMethod : allMethods) {
                    if (allMethod.getName().startsWith("set")) {
                        //获取参数列表
                        Class<?>[] params = allMethod.getParameterTypes();
                        String paraName = allMethod.getName().substring(3, 4).toLowerCase() + allMethod.getName().substring(4);
                        if (!map.containsKey(paraName) && params[0] == Boolean.class) {
                            allMethod.invoke(bean, false);
                        }
                    }
                }

            }
            return bean;
        } catch (InstantiationException | IllegalAccessException | NoSuchFieldException | NoSuchMethodException |
                 ParseException | InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 将请求参数值转化为目标类型
     *
     * @param s    要转化的请求参数
     * @param type 转化的目标类型
     * @return
     */
    private static Object parseValue(String[] s, Class<?> type) throws ParseException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        if (type == String.class) {
            return s[0];
        } else if (type == Integer.class || type == int.class) {
            return Integer.valueOf(s[0]);
        } else if (type == Long.class || type == long.class) {
            return Long.valueOf(s[0]);
        } else if (type == Double.class || type == double.class) {
            return Double.valueOf(s[0]);
        } else if (type == Float.class || type == float.class) {
            return Float.valueOf(s[0]);
        } else if (type == Boolean.class || type == boolean.class) {
            if (s[0] == null || s[0].trim().isEmpty()) {
                return false;
            }
            s[0] = s[0].trim().toLowerCase();
            return s[0].equals("true") || s[0].equals("on") || s[0].equals("yes") || s[0].equals("1");
        } else if (type == Date.class) {
            return new SimpleDateFormat("yyyy-MM-dd").parse(s[0]);
        } else if (type == BigDecimal.class) {
            return type.getDeclaredConstructor(String.class).newInstance(s[0]);
        } else if (type == BigInteger.class) {
            return type.getDeclaredConstructor(String.class).newInstance(s[0]);
        } else if (type == char.class || type == Character.class) {
            return s[0].charAt(0);
        } else if (type == Arrays.class) {
            return s;
        }
        return s;
    }
}
